package com.yeskery.nut.aop.aspect;

import com.yeskery.nut.aop.aspect.joinpoint.LogicAndJoinPoint;
import com.yeskery.nut.aop.aspect.joinpoint.LogicOrJoinPoint;
import com.yeskery.nut.aop.aspect.joinpoint.ReverseJoinPoint;
import com.yeskery.nut.aop.aspect.parser.*;
import com.yeskery.nut.core.NutException;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 切面工厂对象
 * @author Yeskery
 * 2023/8/7
 */
public class AspectFactory {

    /** 逻辑与 */
    private static final String LOGIC_AND = "&&";

    /** 逻辑或 */
    private static final String LOGIC_OR = "||";

    /** 逻辑或正则 */
    private static final String LOGIC_OR_PATTERN = "\\|\\|";

    /** 逻辑非 */
    private static final String REVERSE = "!";

    /** 连接点解析器 */
    private final List<JoinPointParser> joinPointParsers = new ArrayList<>();

    {
        joinPointParsers.add(new ExecutionJoinPointParser());
        joinPointParsers.add(new WithinJoinPointParser());
        joinPointParsers.add(new TargetPointParser());
        joinPointParsers.add(new ArgsJoinPointParser());
        joinPointParsers.add(new AnnotationJoinPointParser());
        joinPointParsers.add(new AnnotationWithinJoinPointParser());
        joinPointParsers.add(new AnnotationTargetPointParser());
        joinPointParsers.add(new AnnotationArgsJoinPointParser());
        joinPointParsers.add(new BeanNameJoinPointParser());
    }

    /**
     * 获取连接点
     * @param express 连接点表达式
     * @return 连接点
     */
    public JoinPoint getJoinPoint(String express) {
        if (!express.contains(LOGIC_AND) && !express.contains(LOGIC_OR)) {
            return findJoinPoint(express);
        }
        if (express.contains(LOGIC_AND) && express.contains(LOGIC_OR)) {
            throw new NutException("UnSupport Logical Operators [&&] [||] Used Together.");
        }

        if (express.contains(LOGIC_AND)) {
            List<JoinPoint> joinPoints = Arrays.stream(express.split(LOGIC_AND))
                    .map(String::trim)
                    .map(this::findJoinPoint)
                    .collect(Collectors.toList());
            return new LogicAndJoinPoint(joinPoints);
        }
        if (express.contains(LOGIC_OR)) {
            List<JoinPoint> joinPoints = Arrays.stream(express.split(LOGIC_OR_PATTERN))
                    .map(String::trim)
                    .map(this::findJoinPoint)
                    .collect(Collectors.toList());
            return new LogicOrJoinPoint(joinPoints);
        }
        throw new NutException("UnSupport JoinPoint Express [" + express + "]");
    }

    /**
     * 从支持的连接点查询指定连接点
     * @param express 连接点表达式
     * @return 连接点
     */
    private JoinPoint findJoinPoint(String express) {
        boolean reverse = express.startsWith(REVERSE);
        JoinPoint joinPoint = null;
        for (JoinPointParser joinPointParser : joinPointParsers) {
            if (joinPointParser.support(reverse ? express.substring(1) : express)) {
                joinPoint = joinPointParser.createJoinPoint(express);
            }
        }
        if (joinPoint == null) {
            throw new NutException("UnSupport JoinPoint For Express[" + express + "].");
        }
        return reverse ? new ReverseJoinPoint(joinPoint) : joinPoint;
    }
}
